package com.edu.buservice.biz.handler;

import cn.dev33.satoken.stp.StpUtil;
import com.edu.buservice.biz.enums.DomainEnum;
import com.edu.buservice.biz.enums.LoginTypeEnum;
import com.edu.buservice.biz.handler.strategy.LoginStrategy;
import com.edu.buservice.biz.model.RequestContext;
import com.edu.buservice.util.model.enums.ErrorCodeEnum;
import com.edu.buservice.util.model.error.BizException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @program: KQAIA
 * @description:
 * @author: 无恙
 * @create: 2025-03-07 21:56
 **/

@Slf4j
@Component
public class IndexHandlerImpl implements IndexHandler {

	private Map<String, LoginStrategy> loginStrategyMap =new ConcurrentHashMap<>();

	@Value("${index.url}")
	private String indexUrl;

	@Value("${login.url}")
	private String loginUrl;

	@Override
	public String index(HttpServletRequest request, HttpServletResponse response) {

		String redirect = request.getParameter("redirect");

		//1.判断是否登录
		if(StpUtil.isLogin()){
			return redirect;
		}

		//2.未登录，跳转到登录页面
		return loginUrl;
	}

	@Override
	public String login(HttpServletRequest request, HttpServletResponse response) {

		log.info("登录请求参数: {}", request.getParameterMap());
		RequestContext requestContext = buildRequestContext(request, response);

		//获取对应处理器
		LoginStrategy loginStrategy = getLoginStrategy(requestContext);


		return loginStrategy.doProcess(requestContext);
	}


	private RequestContext buildRequestContext(HttpServletRequest request, HttpServletResponse response) {
		RequestContext context = new RequestContext();
		context.setRequest(request);
		context.setResponse(response);

		String loginTypeCode = request.getParameter("loginType");
		log.info("登录方式: {}", loginTypeCode);
		LoginTypeEnum loginType = LoginTypeEnum.getByCode(loginTypeCode);

		if (loginType == null) {
			log.error("登录方式或渠道不支持, 请求参数: {}", request.getParameterMap());
			throw new BizException(ErrorCodeEnum.LOGIN_CHANNEL_UNSUPPORTED, "登录方式或渠道不支持");
		}

		context.setLoginType(loginType);

		//获取域
		String domain = request.getParameter("domain");

		DomainEnum byDomain = DomainEnum.getByDomain(domain);

		if (byDomain == null){
			throw new BizException(ErrorCodeEnum.PARAM_ERROR, "域参数错误或者不可以为null");
		}

		context.setDomain(byDomain);

		// 获取重定向地址并进行验证
		String redirect = request.getParameter("redirect");
		if (!isValidRedirectUrl(redirect)) {
			redirect = indexUrl;
		}
		context.setRedirect(redirect);

		// 获取请求参数
		Map<String, String> params = Optional.ofNullable(request.getParameterMap())
				.orElse(Collections.emptyMap())
				.entrySet().stream()
				.collect(Collectors.toMap(
						Map.Entry::getKey,
						entry -> entry.getValue()[0]
				));
		context.setParams(params);

		context.setIp(request.getRemoteAddr());

		return context;
	}

	//获取handler处理器
	private LoginStrategy getLoginStrategy(RequestContext context) {
		String loginTypeCode = context.getLoginType().getCode();
		LoginStrategy loginStrategy = loginStrategyMap.get(loginTypeCode);
		if (loginStrategy == null) {
			throw new BizException(ErrorCodeEnum.LOGIN_CHANNEL_UNSUPPORTED, "登录方式或渠道不支持");
		}
		return loginStrategy;
	}

	// 验证重定向URL是否可信
	private boolean isValidRedirectUrl(String redirectUrl) {
		// 实现具体的验证逻辑，例如检查是否为内部域名或已知的安全域名
		// 这里只是一个示例实现
		return redirectUrl != null && redirectUrl.startsWith("https://example.com/");
	}


	@EventListener
	public void handleContextRefreshedEvent(ContextRefreshedEvent event) {

		//获取所有LoginStrategy实现类
		Map<String, LoginStrategy> beansOfType = event.getApplicationContext().getBeansOfType(LoginStrategy.class);

		log.info("初始化登录处理器={}", beansOfType);

		loginStrategyMap.putAll(beansOfType);
	}
}
